/*
@Time : 2020-01-13 10:45
@Author : wj
@File : logging
@Software: GoLand
*/

package middleware

import (
	"apiserver/handler"
	"apiserver/pkg/errno"
	"bytes"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/lexkong/log"
	"github.com/willf/pad"
	"io/ioutil"
	"regexp"
	"time"
)

type bodyLogWrite struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (w bodyLogWrite) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}

//记录请求日志(此中间件在线上会有内存压力,建议debug模式使用)
func Logging() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now().UTC()  //请求时间
		path := c.Request.URL.Path //请求路径

		reg := regexp.MustCompile("(/v1/user|/login)") //只记指定路由的日志
		if !reg.MatchString(path) {
			return
		}

		// 跳过健康检查请求
		if path == "/sd/health" || path == "/sd/ram" || path == "/sd/cpu" || path == "/sd/disk" {
			return
		}

		// 读取请求整体内容
		bodyBytes, _ := ioutil.ReadAll(c.Request.Body)

		// 将io.ReadCloser恢复到原始状态
		c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

		//基本信息
		method := c.Request.Method
		ip := c.ClientIP()

		blw := &bodyLogWrite{
			body:           bytes.NewBufferString(""),
			ResponseWriter: c.Writer,
		}

		c.Writer = blw

		//继续
		c.Next()

		//计算延迟
		end := time.Now().UTC()
		latency := end.Sub(start)

		code, message := -1, ""

		var response handler.Response

		if err := json.Unmarshal(blw.body.Bytes(), &response); err != nil {
			log.Errorf(err, "response body can not unmarshal to model.Response struct, body: `%s`", blw.body.Bytes())
			code = errno.InternalServerError.Code
			message = err.Error()
		} else {
			code = response.Code
			message = response.Message
		}

		log.Infof("%-13s | %-12s | %s %s | {code: %d, message: %s}", latency, ip, pad.Right(method, 5, ""), path, code, message)
	}
}
